#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<iostream>
#include<errno.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<poll.h>

using namespace std;

#define BUFFER_SIZE 64

int main(){
    const char* ip = "192.168.30.128";
    int port = atoi("1235");

    struct sockaddr_in _server_address;
    bzero(&_server_address,sizeof(_server_address));
    _server_address.sin_family = AF_INET;
    _server_address.sin_port = htons(port);
    inet_pton(AF_INET,ip,&_server_address.sin_addr);
    
    int _sockFD = socket(PF_INET,SOCK_STREAM,0);
    if(_sockFD < 0){
        cout<<"Client socket init ERROR! "<<endl;
        return -1;
    }
    cout<<"Client socket init SUCCESS! "<<endl;

    if(connect(_sockFD,(struct sockaddr*)&_server_address,sizeof(_server_address)) < 0){
        cout<<"Client connect ERROR!"<<endl;
        close(_sockFD);
        return 1;
    }

    pollfd fds[2];
    fds[0].fd = 0;
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    fds[1].fd = _sockFD;
    fds[1].events = POLLIN|POLLHUP;
    fds[1].revents = 0;
    char read_buf[BUFFER_SIZE];
    int pipeFD[2];
    int ret = pipe(pipeFD);
    if(ret == -1){
        cout<<"Client pipe ERROR!"<<endl;
        return -1;
    }
    cout<<"Client pipe SUCCESS!"<<endl;
    while(1){
        ret = poll(fds,2,-1);
        if(ret < 0){
            cout<<"Client poll ERROR!"<<endl;
            break;
        }

        if(fds[1].revents & POLLRDHUP){
            cout<<"Server close the connection!"<<endl;
            break;
        }
        else if(fds[1].revents & POLLIN){
            memset(read_buf,'\0',BUFFER_SIZE);
            recv(fds[1].fd,read_buf,BUFFER_SIZE-1,0);
            cout<<"Receive : "<<read_buf<<endl;
        }

        if(fds[0].revents & POLLIN){
            ret = splice(0,NULL,pipeFD[1],NULL,32768,SPLICE_F_MORE | SPLICE_F_MOVE);
            ret = splice(pipeFD[0],NULL,_sockFD,NULL,32768,SPLICE_F_MORE | SPLICE_F_MOVE);
        }
    }

    close(_sockFD);
    return 0;
}